From 05255bfc90310445dae52683ce45729e599d078b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 7 Aug 2020 09:21:29 -0400 Subject: [PATCH] gtk-demo: Modernize source highlighting Drop the homegrown highlighting code, and just use highlight to produce Pango markup. When using an external highlighter, we can also highlight css, xml, headers, at least. --- demos/gtk-demo/main.c | 447 +++++++++--------------------------------- 1 file changed, 93 insertions(+), 354 deletions(-) diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c index 95541fcfd9..1589b3d4bc 100644 --- a/demos/gtk-demo/main.c +++ b/demos/gtk-demo/main.c @@ -234,373 +234,106 @@ activate_run (GSimpleAction *action, gtk_demo_run (demo, window); } -/* Stupid syntax highlighting. - * - * No regex was used in the making of this highlighting. - * It should only work for simple cases. This is good, as - * that's all we should have in the demos. - */ -/* This code should not be used elsewhere, except perhaps as an example of how - * to iterate through a text buffer. - */ -enum { - STATE_NORMAL, - STATE_IN_COMMENT -}; - -static const char *tokens[] = -{ - "/*", - "\"", - NULL -}; - -static const char *types[] = +static GBytes * +fontify_text (const char *format, + const char *text) { - "static", - "const ", - "void", - " int ", - " char ", - "char ", - "float", - "double", - "gint8", - "gint16", - "gint32", - "guint", - "guint8", - "guint16", - "guint32", - "guchar", - "glong", - "gboolean" , - "gshort", - "gushort", - "gulong", - "gpointer", - "NULL", - "GList", - "GSList", - "FALSE", - "TRUE", - "FILE ", - "GtkColorSelection ", - "GtkWidget ", - "GtkButton ", - "GdkColor ", - "GdkRectangle ", - "GdkEventExpose ", - "GdkGC ", - "GdkPixbufLoader ", - "GdkPixbuf ", - "GError", - "size_t", - "GtkAboutDialog ", - "GtkAction ", - "GtkActionEntry ", - "GtkRadioActionEntry ", - "GtkIconFactory ", - "GtkTextBuffer ", - "GtkStatusbar ", - "GtkTextIter ", - "GtkTextMark ", - "GdkEventWindowState ", - "GtkActionGroup ", - "GtkUIManager ", - "GtkRadioAction ", - "GtkActionClass ", - "GtkToggleActionEntry ", - "GtkAssistant ", - "GtkBuilder ", - "GtkSizeGroup ", - "GtkTreeModel ", - "GtkTreeSelection ", - "GdkDisplay ", - "GdkScreen ", - "GdkSurface ", - "GdkEventButton ", - "GdkCursor ", - "GtkTreeIter ", - "GtkTreeViewColumn ", - "GdkDisplayManager ", - "GdkClipboard ", - "GtkIconSize ", - "GtkImage ", - "GdkDragContext ", - "GtkSelectionData ", - "GtkDialog ", - "GtkMenuItem ", - "GtkListStore ", - "GtkCellLayout ", - "GtkCellRenderer ", - "GtkTreePath ", - "GtkTreeStore ", - "GtkEntry ", - "GtkEditable ", - "GtkEditableInterface ", - "GdkPixmap ", - "GdkEventConfigure ", - "GdkEventMotion ", - "GdkModifierType ", - "GtkEntryCompletion ", - "GtkToolItem ", - "GDir ", - "GtkIconView ", - "GtkCellRendererText ", - "GtkContainer ", - "GtkPaned ", - "GtkPrintOperation ", - "GtkPrintContext ", - "cairo_t ", - "PangoLayout " - "PangoFontDescription ", - "PangoRenderer ", - "PangoMatrix ", - "PangoContext ", - "PangoLayout ", - "GtkToggleButton ", - "GString ", - "GtkIconSize ", - "GtkTreeView ", - "GtkTextTag ", - "GdkEvent ", - "GdkEventKey ", - "GtkTextView ", - "GdkBitmap ", - "GtkTextChildAnchor ", - "GArray ", - "GtkCellEditable ", - "GtkCellRendererToggle ", - NULL -}; - -static const char *control[] = -{ - " if ", - " while ", - " else", - " do ", - " for ", - "?", - ":", - "return ", - "goto ", - NULL -}; -void -parse_chars (char *text, - char **end_ptr, - int *state, - const char **tag, - gboolean start) -{ - int i; - char *next_token; - - /* Handle comments first */ - if (*state == STATE_IN_COMMENT) + GSubprocess *subprocess; + static gboolean warned = FALSE; + GBytes *stdin_buf; + GBytes *stdout_buf = NULL; + GBytes *stderr_buf = NULL; + GError *error = NULL; + char *format_arg; + + format_arg = g_strconcat ("--syntax=", format, NULL); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | + G_SUBPROCESS_FLAGS_STDOUT_PIPE | + G_SUBPROCESS_FLAGS_STDERR_PIPE, + &error, + "highlight", + format_arg, + "--out-format=pango", + NULL); + g_free (format_arg); + + if (!subprocess) { - *end_ptr = strstr (text, "*/"); - if (*end_ptr) + if (!warned) { - *end_ptr += 2; - *state = STATE_NORMAL; - *tag = "comment"; + g_warning ("%s", error->message); + warned = TRUE; } - return; + g_clear_error (&error); + + return NULL; } - *tag = NULL; - *end_ptr = NULL; + stdin_buf = g_bytes_new_static (text, strlen (text)); - /* check for comment */ - if (!strncmp (text, "/*", 2)) + if (!g_subprocess_communicate (subprocess, + stdin_buf, + NULL, + &stdout_buf, + &stderr_buf, + &error)) { - *end_ptr = strstr (text, "*/"); - if (*end_ptr) - *end_ptr += 2; - else - *state = STATE_IN_COMMENT; - *tag = "comment"; - return; - } + g_clear_pointer (&stdin_buf, g_bytes_unref); + g_clear_pointer (&stdout_buf, g_bytes_unref); + g_clear_pointer (&stderr_buf, g_bytes_unref); - /* check for preprocessor defines */ - if (*text == '#' && start) - { - *end_ptr = NULL; - *tag = "preprocessor"; - return; - } + g_warning ("%s", error->message); + g_clear_error (&error); - /* functions */ - if (start && * text != '\t' && *text != ' ' && *text != '{' && *text != '}') - { - if (strstr (text, "(")) - { - *end_ptr = strstr (text, "("); - *tag = "function"; - return; - } + return NULL; } - /* check for types */ - for (i = 0; types[i] != NULL; i++) - if (!strncmp (text, types[i], strlen (types[i])) || - (start && types[i][0] == ' ' && !strncmp (text, types[i] + 1, strlen (types[i]) - 1))) - { - *end_ptr = text + strlen (types[i]); - *tag = "type"; - return; - } - - /* check for control */ - for (i = 0; control[i] != NULL; i++) - if (!strncmp (text, control[i], strlen (control[i]))) - { - *end_ptr = text + strlen (control[i]); - *tag = "control"; - return; - } - - /* check for string */ - if (text[0] == '"') - { - int maybe_escape = FALSE; - *end_ptr = text + 1; - *tag = "string"; - while (**end_ptr != '\000') - { - if (**end_ptr == '\"' && !maybe_escape) - { - *end_ptr += 1; - return; - } - if (**end_ptr == '\\') - maybe_escape = TRUE; - else - maybe_escape = FALSE; - *end_ptr += 1; - } - return; - } + g_bytes_unref (stdin_buf); - /* not at the start of a tag. Find the next one. */ - for (i = 0; tokens[i] != NULL; i++) + if (g_subprocess_get_exit_status (subprocess) != 0) { - next_token = strstr (text, tokens[i]); - if (next_token) - { - if (*end_ptr) - *end_ptr = (*end_ptr